home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / ply15dat.zip / LIB.C < prev    next >
C/C++ Source or Header  |  1992-10-17  |  60KB  |  1,733 lines

  1. /*
  2.  * lib.c - a library of vector operations, a random number generator, and
  3.  *     object output routines.
  4.  *
  5.  * Version:  2.2 (11/17/87)
  6.  * Author:  Eric Haines, 3D/Eye, Inc.
  7.  *
  8.  * Modified: 1 October 1992
  9.  *           Alexander R. Enzmann
  10.  *
  11.  *           I made quite a few changes in order to support multiple raytracers,
  12.  *           with the hopes that this library would become even more useful than
  13.  *           it already is.
  14.  */
  15.  
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <math.h>
  19. #include <string.h>
  20. #include "def.h"
  21. #include "lib.h"
  22.  
  23. /* Here are some local variables that are used to control things like
  24.    the current output file, current texture, ... */
  25. static FILE *outfile      = stdout;
  26. static char *texture_name = NULL;
  27. static int  texture_count = 0;
  28. static int  format        = OUTPUT_POVRAY;
  29. static int  u_resolution  = OUTPUT_RESOLUTION;
  30. static int  v_resolution  = OUTPUT_RESOLUTION;
  31. static COORD4 view_from   = {0.0, 0.0, -5.0, 1.0};
  32. static COORD4 view_at     = {0.0, 0.0, 0.0, 1.0};
  33. static COORD4 view_up     = {0.0, 0.0, 1.0, 1.0};
  34. static double view_angle  = 45;
  35. static double view_hither = 0.001;
  36. static double view_aspect = 1.0;
  37. static int view_resx = 128;
  38. static int view_resy = 128;
  39. static COORD4 bk_color = {0.0, 0.0, 0.0, 0.0};
  40. static COORD4 fg_color = {0.0, 0.0, 0.0, 0.0};
  41.  
  42. /* Display a matrix */
  43. static void
  44. show_tx(descrip, tx)
  45.    char *descrip;
  46.    MATRIX tx;
  47. {
  48.    int i, j, offset = strlen(descrip);
  49.    printf("%s", descrip);
  50.    printf("[ %10.6g %10.6g %10.6g %10.6g]\n",
  51.       tx[0][0], tx[0][1], tx[0][2], tx[0][3]);
  52.    for (i=1;i<4;i++) {
  53.       for (j=0;j<offset;j++)
  54.      printf(" ");
  55.       printf("[ %10.6g %10.6g %10.6g %10.6g]\n",
  56.          tx[i][0], tx[i][1], tx[i][2], tx[i][3]);
  57.       }
  58. }
  59.  
  60. /*
  61.  * Normalize the vector (X,Y,Z) so that X*X + Y*Y + Z*Z = 1.
  62.  *
  63.  * The normalization divisor is returned.  If the divisor is zero, no
  64.  * normalization occurs.
  65.  *
  66.  */
  67. double
  68. lib_normalize_coord3(cvec)
  69.    COORD4 *cvec;
  70. {
  71.    double divisor;
  72.  
  73.    divisor = sqrt( (double)DOT_PRODUCT( (*cvec), (*cvec) ) ) ;
  74.    if (divisor != 0.0 ) {
  75.       cvec->x /= divisor;
  76.       cvec->y /= divisor;
  77.       cvec->z /= divisor;
  78.       }
  79.     return divisor;
  80. }
  81.  
  82.  
  83. /*
  84.  * Set all matrix elements to zero.
  85.  */
  86. void
  87. lib_zero_matrix(mx)
  88.    MATRIX mx;
  89. {
  90.    long i, j;
  91.  
  92.    for (i=0;i<4;++i)
  93.       for (j=0;j<4;++j)
  94.          mx[i][j] = 0.0;
  95. }
  96.  
  97. /*
  98.  * Create identity matrix.
  99.  */
  100. void
  101. lib_create_identity_matrix(mx)
  102.    MATRIX mx;
  103. {
  104.    int i;
  105.  
  106.    lib_zero_matrix(mx);
  107.    for (i=0;i<4;++i)
  108.       mx[i][i] = 1.0;
  109. }
  110.  
  111. /*
  112.  * Create a rotation matrix along the given axis by the given angle in radians.
  113.  */
  114. void
  115. lib_create_rotate_matrix(mx, axis, angle)
  116.    MATRIX mx;
  117.    int axis;
  118.    double angle;
  119. {
  120.    double cosine, sine;
  121.  
  122.    lib_zero_matrix(mx);
  123.    cosine = cos((double)angle);
  124.    sine = sin((double)angle);
  125.    switch (axis) {
  126.       case X_AXIS:
  127.          mx[0][0] = 1.0;
  128.          mx[1][1] = cosine;
  129.          mx[2][2] = cosine;
  130.          mx[1][2] = sine;
  131.          mx[2][1] = -sine;
  132.          break ;
  133.       case Y_AXIS:
  134.          mx[1][1] = 1.0;
  135.          mx[0][0] = cosine;
  136.          mx[2][2] = cosine;
  137.          mx[2][0] = sine;
  138.          mx[0][2] = -sine;
  139.          break;
  140.       case Z_AXIS:
  141.          mx[2][2] = 1.0;
  142.          mx[0][0] = cosine;
  143.          mx[1][1] = cosine;
  144.          mx[0][1] = sine;
  145.          mx[1][0] = -sine;
  146.          break;
  147.       }
  148.    mx[3][3] = 1.0;
  149. }
  150.  
  151. /*
  152.  * Create a rotation matrix along the given axis by the given angle in radians.
  153.  * The axis is a set of direction cosines.
  154.  */
  155. void
  156. lib_create_axis_rotate_matrix(mx, rvec, angle)
  157.    MATRIX mx;
  158.    COORD4 *rvec;
  159.    double angle;
  160. {
  161.    COORD4  axis;
  162.    double  cosine, one_minus_cosine, sine;
  163.  
  164.    COPY_COORD(axis, (*rvec));
  165.    cosine = cos((double)angle);
  166.    sine = sin((double)angle);
  167.    one_minus_cosine = 1.0 - cosine;
  168.  
  169.    mx[0][0] = SQR(axis.x) + (1.0 - SQR(axis.x)) * cosine;
  170.    mx[0][1] = axis.x * axis.y * one_minus_cosine + axis.z * sine;
  171.    mx[0][2] = axis.x * axis.z * one_minus_cosine - axis.y * sine;
  172.    mx[0][3] = 0.0;
  173.  
  174.    mx[1][0] = axis.x * axis.y * one_minus_cosine - axis.z * sine;
  175.    mx[1][1] = SQR(axis.y) + (1.0 - SQR(axis.y)) * cosine;
  176.    mx[1][2] = axis.y * axis.z * one_minus_cosine + axis.x * sine;
  177.    mx[1][3] = 0.0;
  178.  
  179.    mx[2][0] = axis.x * axis.z * one_minus_cosine + axis.y * sine;
  180.    mx[2][1] = axis.y * axis.z * one_minus_cosine - axis.x * sine;
  181.    mx[2][2] = SQR(axis.z) + (1.0 - SQR(axis.z)) * cosine;
  182.    mx[2][3] = 0.0;
  183.  
  184.    mx[3][0] = 0.0;
  185.    mx[3][1] = 0.0;
  186.    mx[3][2] = 0.0;
  187.    mx[3][3] = 1.0;
  188. }
  189.  
  190. /* Create translation matrix */
  191. void
  192. lib_create_translate_matrix(mx, vec)
  193.    MATRIX mx;
  194.    COORD4 *vec;
  195. {
  196.     int i;
  197.     lib_create_identity_matrix(mx);
  198.     mx[3][0] = vec->x;
  199.     mx[3][1] = vec->y;
  200.     mx[3][2] = vec->z;
  201. }
  202.  
  203. /* Create scaling matrix */
  204. void
  205. lib_create_scale_matrix(mx, vec)
  206.    MATRIX mx;
  207.    COORD4 *vec;
  208. {
  209.     int i;
  210.     lib_zero_matrix(mx);
  211.     mx[0][0] = vec->x;
  212.     mx[1][1] = vec->y;
  213.     mx[2][2] = vec->z;
  214. }
  215.  
  216. /* Given a point and a direction, find the transform that brings a point
  217.    in a canonical coordinate system into a coordinate system defined by
  218.    that position and direction.  Both the forward and inverse transform
  219.    matrices are calculated. */
  220. void
  221. lib_create_canonical_matrix(trans, itrans, origin, up)
  222.    MATRIX trans, itrans;
  223.    COORD4 *origin;
  224.    COORD4 *up;
  225. {
  226.    MATRIX trans1, trans2;
  227.    COORD4 tmpv;
  228.    double ang;
  229.  
  230.    /* Translate "origin" to <0, 0, 0> */
  231.    SET_COORD(tmpv, -origin->x, -origin->y, -origin->z);
  232.    lib_create_translate_matrix(trans1, &tmpv);
  233.  
  234.    /* Determine the axis to rotate about */
  235.    if (fabs(up->z) == 1.0)
  236.       SET_COORD4(tmpv, 1.0, 0.0, 0.0, 1.0)
  237.    else
  238.       SET_COORD4(tmpv, -up->y, up->x, 0.0, 1.0)
  239.    lib_normalize_coord3(&tmpv);
  240.    ang = acos(up->z);
  241.  
  242.    /* Calculate the forward matrix */
  243.    lib_create_axis_rotate_matrix(trans2, &tmpv, -ang);
  244.    lib_matrix_multiply(trans, trans1, trans2);
  245.  
  246.    /* Calculate the inverse transform */
  247.    lib_create_axis_rotate_matrix(trans1, &tmpv, ang);
  248.    lib_create_translate_matrix(trans2, origin);
  249.    lib_matrix_multiply(itrans, trans1, trans2);
  250. }
  251.  
  252. /*
  253.  * Multiply a 4 element vector by a matrix.
  254.  */
  255. void
  256. lib_transform_coord(vres, vec, mx)
  257.    COORD4 *vres, *vec;
  258.    MATRIX mx;
  259. {
  260.    vres->x = vec->x*mx[0][0]+vec->y*mx[1][0]+vec->z*mx[2][0]+vec->w*mx[3][0];
  261.    vres->y = vec->x*mx[0][1]+vec->y*mx[1][1]+vec->z*mx[2][1]+vec->w*mx[3][1];
  262.    vres->z = vec->x*mx[0][2]+vec->y*mx[1][2]+vec->z*mx[2][2]+vec->w*mx[3][2];
  263.    vres->w = vec->x*mx[0][3]+vec->y*mx[1][3]+vec->z*mx[2][3]+vec->w*mx[3][3];
  264. }
  265.  
  266. /*
  267.  * Multiply two 4x4 matrices.
  268.  */
  269. void
  270. lib_matrix_multiply(mxres, mx1, mx2)
  271.    MATRIX mxres, mx1, mx2;
  272. {
  273.    int i, j;
  274.  
  275.    for (i=0;i<4;i++)
  276.       for (j=0;j<4;j++)
  277.          mxres[i][j] = mx1[i][0]*mx2[0][j] + mx1[i][1]*mx2[1][j] +
  278.                        mx1[i][2]*mx2[2][j] + mx1[i][3]*mx2[3][j];
  279. }
  280.  
  281. /*
  282.  * Rotate a vector pointing towards the major-axis faces (i.e. the major-axis
  283.  * component of the vector is defined as the largest value) 90 degrees to
  284.  * another cube face.  Mod_face is a face number.
  285.  *
  286.  * If the routine is called six times, with mod_face=0..5, the vector will be
  287.  * rotated to each face of a cube.  Rotations are:
  288.  *     mod_face = 0 mod 3, +Z axis rotate
  289.  *     mod_face = 1 mod 3, +X axis rotate
  290.  *     mod_face = 2 mod 3, -Y axis rotate
  291.  */
  292. void
  293. lib_rotate_cube_face(vec, major_axis, mod_face)
  294.    COORD4 *vec;
  295.    int major_axis, mod_face;
  296. {
  297.    double swap;
  298.  
  299.    mod_face = (mod_face+major_axis) % 3 ;
  300.    if (mod_face == 0) {
  301.       swap   = vec->x;
  302.       vec->x = -vec->y;
  303.       vec->y = swap;
  304.       }
  305.    else if (mod_face == 1) {
  306.       swap   = vec->y;
  307.       vec->y = -vec->z;
  308.       vec->z = swap;
  309.       }
  310.    else {
  311.       swap   = vec->x;
  312.       vec->x = -vec->z;
  313.       vec->z = swap;
  314.       }
  315. }
  316.  
  317. /*
  318.  * Portable gaussian random number generator (from "Numerical Recipes", GASDEV)
  319.  * Returns a uniform random deviate between 0.0 and 1.0.  'iseed' must be
  320.  * less than M1 to avoid repetition, and less than (2**31-C1)/A1 [= 300718]
  321.  * to avoid overflow.
  322.  */
  323. #define M1  134456
  324. #define IA1   8121
  325. #define IC1  28411
  326. #define RM1 1.0/M1
  327.  
  328. double
  329. lib_gauss_rand(iseed)
  330.    long iseed;
  331. {
  332.    double fac, v1, v2, r;
  333.    long   ix1, ix2;
  334.  
  335.    ix2 = iseed;
  336.    do {
  337.       ix1 = (IC1+ix2*IA1) % M1;
  338.       ix2 = (IC1+ix1*IA1) % M1;
  339.       v1 = ix1 * 2.0 * RM1 - 1.0;
  340.       v2 = ix2 * 2.0 * RM1 - 1.0;
  341.       r = v1*v1 + v2*v2;
  342.       } while ( r >= 1.0 );
  343.  
  344.    fac = sqrt((double)(-2.0 * log((double)r) / r));
  345.    return v1 * fac;
  346. }
  347.  
  348. /*
  349.  * Routines to set/reset the various output parameters
  350.  */
  351. void
  352. lib_set_output_file(new_outfile)
  353.    FILE *new_outfile;
  354. {
  355.    if (new_outfile == NULL)
  356.       outfile = stdout;
  357.    else
  358.       outfile = new_outfile;
  359. }
  360.  
  361. void
  362. lib_set_default_texture(default_texture)
  363.    char *default_texture;
  364. {
  365.    texture_name = default_texture;
  366. }
  367.  
  368. void
  369. lib_set_raytracer(default_tracer)
  370.    int default_tracer;
  371. {
  372.    format = default_tracer;
  373. }
  374.  
  375. void
  376. lib_set_polygonalization(u_steps, v_steps)
  377.    int u_steps, v_steps;
  378. {
  379.    if (u_steps > 0 && v_steps > 0) {
  380.       u_resolution = u_steps;
  381.       v_resolution = v_steps;
  382.       }
  383. }
  384.  
  385. /* OUTPUT ROUTINES */
  386.  
  387. /*
  388.  * Output viewpoint location.  The parameters are:
  389.  *   From:  the eye location.
  390.  *   At:  a position to be at the center of the image.  A.k.a. "lookat"
  391.  *   Up:  a vector defining which direction is up.
  392.  *
  393.  * Note that no assumptions are made about normalizing the data (e.g. the
  394.  * from-at distance does not have to be 1).  Also, vectors are not
  395.  * required to be perpendicular to each other.
  396.  *
  397.  * For all databases some viewing parameters are always the same:
  398.  *
  399.  *   Viewing angle is defined as from the center of top pixel row to bottom
  400.  *     pixel row and left column to right column.
  401.  *   Yon is "at infinity."
  402.  *   Resolution is always 512 x 512.
  403.  */
  404. void
  405. lib_output_viewpoint(from, at, up,
  406.              fov_angle, aspect_ratio, hither,
  407.              resx, resy)
  408.    COORD4 *from, *at, *up;
  409.    double fov_angle, aspect_ratio, hither;
  410.    int    resx, resy;
  411. {
  412.    COORD4 viewvec, rightvec;
  413.    double frustrumheight, frustrumwidth;
  414.  
  415.    switch (format) {
  416.       case OUTPUT_VIDEO:
  417.      /* For now we are just saving the values - what should be done
  418.         is to generate the perspective transformation matrix for the
  419.         given values to the screen. */
  420.      COPY_COORD4(view_from, *from);
  421.      COPY_COORD4(view_at, *at);
  422.      COPY_COORD4(view_up, *up);
  423.      view_angle  = fov_angle;
  424.      view_hither = hither;
  425.      view_resx   = resx;
  426.      view_resy   = resy;
  427.      view_aspect = aspect_ratio;
  428.      break;
  429.       case OUTPUT_NFF:
  430.          fprintf(outfile, "v\n");
  431.          fprintf(outfile, "from %g %g %g\n", from->x, from->y, from->z);
  432.          fprintf(outfile, "at %g %g %g\n", at->x, at->y, at->z);
  433.          fprintf(outfile, "up %g %g %g\n", up->x, up->y, up->z);
  434.          fprintf(outfile, "angle %g\n", fov_angle);
  435.          fprintf(outfile, "hither %g\n", hither);
  436.          fprintf(outfile, "resolution %d %d\n", resx, resy);
  437.          break;
  438.       case OUTPUT_POVRAY:
  439.       case OUTPUT_POVRAY_15:
  440.      /* Lets get a set of vectors that are all at right angles to each
  441.         other that describe the view given. */
  442.      lib_normalize_coord3(up);
  443.          SUB3_COORD(viewvec, *at, *from);
  444.      lib_normalize_coord3(&viewvec);
  445.          CROSS(rightvec, *up, viewvec);
  446.      lib_normalize_coord3(&rightvec);
  447.      CROSS(*up, viewvec, rightvec);
  448.      lib_normalize_coord3(up);
  449.  
  450.      /* Calculate the height of the view frustrum in world coordinates.
  451.         and then scale the right and up vectors appropriately. */
  452.      frustrumheight = 2.0 * tan(PI * fov_angle / 360.0);
  453.      frustrumwidth = aspect_ratio * frustrumheight;
  454.      up->x *= frustrumheight;
  455.      up->y *= frustrumheight;
  456.      up->z *= frustrumheight;
  457.      rightvec.x *= frustrumwidth;
  458.      rightvec.y *= frustrumwidth;
  459.      rightvec.z *= frustrumwidth;
  460.  
  461.      fprintf(outfile, "camera {\n");
  462.      if (format == OUTPUT_POVRAY) {
  463.         fprintf(outfile, "  location <%g %g %g>\n",
  464.             from->x, from->y, from->z);
  465.         fprintf(outfile, "  direction <%g %g %g>\n",
  466.             viewvec.x, viewvec.y, viewvec.z);
  467.         fprintf(outfile, "  right <%g %g %g>\n",
  468.             rightvec.x, rightvec.y, rightvec.z);
  469.         fprintf(outfile, "  up <%g %g %g>\n",
  470.             up->x, up->y, up->z);
  471.         }
  472.      else {
  473.         fprintf(outfile, "  location <%g, %g, %g>\n",
  474.             from->x, from->y, from->z);
  475.         fprintf(outfile, "  direction <%g, %g, %g>\n",
  476.             viewvec.x, viewvec.y, viewvec.z);
  477.         fprintf(outfile, "  right <%g, %g, %g>\n",
  478.             rightvec.x, rightvec.y, rightvec.z);
  479.         fprintf(outfile, "  up <%g, %g, %g>\n",
  480.             up->x, up->y, up->z);
  481.         }
  482.      fprintf(outfile, "  }\n");
  483.          break;
  484.       case OUTPUT_POLYRAY:
  485.          fprintf(outfile, "viewpoint {\n");
  486.          fprintf(outfile, "   from <%g, %g, %g>\n", from->x, from->y, from->z);
  487.          fprintf(outfile, "   at <%g, %g, %g>\n", at->x, at->y, at->z);
  488.          fprintf(outfile, "   up <%g, %g, %g>\n", up->x, up->y, up->z);
  489.          fprintf(outfile, "   angle %g\n", fov_angle);
  490.          fprintf(outfile, "   aspect %g\n", aspect_ratio);
  491.          fprintf(outfile, "   hither %g\n", hither);
  492.          fprintf(outfile, "   resolution %d, %d\n", resx, resy);
  493.          fprintf(outfile, "   }\n");
  494.          break;
  495.       case OUTPUT_VIVID:
  496.          fprintf(outfile, "studio = {\n");
  497.          fprintf(outfile, "   from = %g %g %g;\n", from->x, from->y, from->z);
  498.          fprintf(outfile, "   at = %g %g %g;\n", at->x, at->y, at->z);
  499.          fprintf(outfile, "   up = %g %g %g;\n", up->x, up->y, up->z);
  500.          fprintf(outfile, "   angle = %g;\n", fov_angle);
  501.          fprintf(outfile, "   aspect = %g;\n", aspect_ratio);
  502.          fprintf(outfile, "   resolution = %d %d;\n", resx, resy);
  503.          fprintf(outfile, "   }\n");
  504.          break;
  505.       case OUTPUT_QRT:
  506.          fprintf(outfile, "OBSERVER = (\n");
  507.          fprintf(outfile, "   loc = (%g,%g,%g),\n", from->x, from->y, from->z);
  508.          fprintf(outfile, "   lookat = (%g,%g,%g),\n", at->x, at->y, at->z);
  509.          fprintf(outfile, "   up = (%g,%g,%g) )\n", up->x, up->y, up->z);
  510.      fprintf(outfile, "FOC_LENGTH = %g\n",
  511.                  35.0 / tan(PI * fov_angle / 360.0));
  512.      fprintf(outfile, "DEFAULT (\n");
  513.          fprintf(outfile, "   aspect = %g,\n", 6.0 * aspect_ratio / 7.0);
  514.          fprintf(outfile, "   x_res = %d, y_res = %d )\n", resx, resy);
  515.  
  516.          /* QRT insists on having the output file as part of the data text */
  517.          fprintf(outfile, "FILE_NAME = qrt.tga\n");
  518.          break;
  519.       case OUTPUT_RAYSHADE:
  520.          fprintf(outfile, "eyep %g %g %g\n", from->x, from->y, from->z);
  521.          fprintf(outfile, "lookp %g %g %g\n", at->x, at->y, at->z);
  522.          fprintf(outfile, "up %g %g %g\n", up->x, up->y, up->z);
  523.          fprintf(outfile, "fov %g %g\n", aspect_ratio * fov_angle, fov_angle);
  524.          fprintf(outfile, "screen %d %d\n", resx, resy);
  525.          fprintf(outfile, "sample 1 nojitter\n");
  526.          break;
  527.        }
  528. }
  529.  
  530. /*
  531.  * Output light.  A light is defined by position.  All lights have the same
  532.  * intensity.
  533.  *
  534.  */
  535. void
  536. lib_output_light(center_pt)
  537.    COORD4 *center_pt;
  538. {
  539.    double lscale;
  540.    if (center_pt->w != 0.0)
  541.       lscale = center_pt->w;
  542.    else
  543.       lscale = 1.0;
  544.  
  545.    switch (format) {
  546.       case OUTPUT_VIDEO:
  547.      /* Not currently doing anything with lights */
  548.      break;
  549.       case OUTPUT_NFF:
  550.          fprintf(outfile, "l %g %g %g\n",
  551.                  center_pt->x, center_pt->y, center_pt->z ) ;
  552.          break;
  553.       case OUTPUT_POVRAY:
  554.      fprintf(outfile, "object { ");
  555.          fprintf(outfile,
  556.                  "light_source { <%g %g %g> color red %g green %g blue %g }",
  557.                  center_pt->x, center_pt->y, center_pt->z,
  558.                  lscale, lscale, lscale);
  559.      fprintf(outfile, "}\n");
  560.          break;
  561.       case OUTPUT_POVRAY_15:
  562.      fprintf(outfile, "object { ");
  563.          fprintf(outfile,
  564.                  "light_source { <%g, %g, %g> color red %g green %g blue %g }",
  565.                  center_pt->x, center_pt->y, center_pt->z,
  566.                  lscale, lscale, lscale);
  567.      fprintf(outfile, "}\n");
  568.          break;
  569.       case OUTPUT_POLYRAY:
  570.          fprintf(outfile, "light <%g, %g, %g>, <%g, %g, %g>\n",
  571.                  lscale, lscale, lscale,
  572.                  center_pt->x, center_pt->y, center_pt->z);
  573.          break;
  574.       case OUTPUT_VIVID:
  575.          fprintf(outfile, "light = {type=point; position = %g %g %g;",
  576.                  center_pt->x, center_pt->y, center_pt->z );
  577.          fprintf(outfile, " color = %g %g %g;}\n",
  578.                  lscale, lscale, lscale);
  579.          break;
  580.       case OUTPUT_QRT:
  581.          fprintf(outfile, "LAMP ( loc = (%g,%g,%g), dist = 0, radius = 1,",
  582.                  center_pt->x, center_pt->y, center_pt->z );
  583.          fprintf(outfile, " amb = (%g,%g,%g) )\n",
  584.                  lscale, lscale, lscale);
  585.          break;
  586.       case OUTPUT_RAYSHADE:
  587.          fprintf(outfile, "light %g point %g %g %g\n",
  588.                  center_pt->w, center_pt->x, center_pt->y, center_pt->z);
  589.          break;
  590.       }
  591. }
  592.  
  593. /*
  594.  * Output background color.  A color is simply RGB (monitor dependent, but
  595.  * that's life).
  596.  */
  597. void
  598. lib_output_background_color(color)
  599.    COORD4 *color;
  600. {
  601.    switch (format) {
  602.       case OUTPUT_VIDEO:
  603.      COPY_COORD4(bk_color, *color);
  604.      break;
  605.       case OUTPUT_NFF:
  606.          fprintf(outfile, "b %g %g %g\n", color->x, color->y, color->z);
  607.          break;
  608.       case OUTPUT_POVRAY:
  609.       case OUTPUT_POVRAY_15:
  610.          /* POV-Ray 1.0/1.5 do not support a background color */
  611.          break;
  612.       case OUTPUT_POLYRAY:
  613.          fprintf(outfile, "background <%g, %g, %g>\n",
  614.                  color->x, color->y, color->z);
  615.          break;
  616.       case OUTPUT_VIVID:
  617.          /* Vivid insists on putting the background into the studio */
  618.          fprintf(outfile, "studio = { background = %g %g %g; }\n",
  619.                  color->x, color->y, color->z);
  620.          break;
  621.       case OUTPUT_QRT:
  622.          fprintf(outfile, "SKY ( horiz = (%g,%g,%g), zenith = (%g,%g,%g),",
  623.                  color->x, color->y, color->z,
  624.                  color->x, color->y, color->z);
  625.          fprintf(outfile, " dither = 0 )\n");
  626.          break;
  627.       case OUTPUT_RAYSHADE:
  628.          fprintf(outfile, "background %g %g %g\n",
  629.                  color->x, color->y, color->z);
  630.          break;
  631.       }
  632. }
  633.  
  634. /*
  635.  * Output color and shading parameters for all following objects
  636.  *
  637.  * For POV-Ray and Polyray, a character string will be returned that
  638.  * identified this texture.  The default texture will be updated with
  639.  * the name generated by this function.
  640.  *
  641.  * Meaning of the color and shading parameters:
  642.  *    color  = surface color
  643.  *    ka     = ambient component
  644.  *    kd     = diffuse component
  645.  *    ks     = amount contributed from the reflected direction
  646.  *    shine  = contribution from specular highlights
  647.  *    ang    = angle at which the specular highlight falls to 50% of maximum
  648.  *    t      = amount from the refracted direction
  649.  *    i_of_r = index of refraction of the surface
  650.  *
  651.  */
  652. char *
  653. lib_output_color(color, ka, kd, ks, shine, ang, t, i_of_r)
  654.    COORD4 *color;
  655.    double ka, kd, ks, shine, ang, t, i_of_r;
  656. {
  657.    char *txname = NULL;
  658.    double phong_pow;
  659.  
  660.    /* Calculate the Phong coefficient */
  661.    phong_pow = PI * ang / 180.0;
  662.    if (phong_pow <= 0.0)
  663.       phong_pow = 100000.0;
  664.    else if (phong_pow >= (PI/4.0))
  665.       phong_pow = 0.000001;
  666.    else
  667.       phong_pow = -(log(2.0) / log(cos(2.0 * phong_pow)));
  668.  
  669.    switch (format) {
  670.       case OUTPUT_VIDEO:
  671.      COPY_COORD4(fg_color, *color);
  672.      break;
  673.       case OUTPUT_NFF:
  674.          fprintf(outfile, "f %g %g %g %g %g %g %g %g\n",
  675.                  color->x, color->y, color->z, kd, ks, phong_pow, t, i_of_r);
  676.          break;
  677.       case OUTPUT_POVRAY:
  678.       case OUTPUT_POVRAY_15:
  679.          txname = (char *)malloc(7*sizeof(char));
  680.          if (txname == NULL) {
  681.             fprintf(outfile, "Failed to allocate texture name %d\n",
  682.                    texture_count);
  683.             exit(1);
  684.             }
  685.          sprintf(txname, "txt%03d", texture_count++);
  686.          txname[6] = '\0';
  687.      fprintf(outfile, "#declare %s = texture {\n", txname);
  688.      if (format == OUTPUT_POVRAY_15)
  689.         fprintf(outfile, "   pigment {\n");
  690.          if (t > 0)
  691.         fprintf(outfile, "   color red %g green %g blue %g alpha 1.0\n",
  692.                     color->x, color->y, color->z);
  693.          else
  694.         fprintf(outfile, "   color red %g green %g blue %g\n",
  695.                     color->x, color->y, color->z);
  696.      if (format == OUTPUT_POVRAY_15) {
  697.         fprintf(outfile, "   }\n");
  698.         fprintf(outfile, "   finish {\n");
  699.         }
  700.      fprintf(outfile, "   ambient %g\n", ka);
  701.      fprintf(outfile, "   diffuse %g\n", kd);
  702.      if (shine != 0)
  703.         fprintf(outfile, "   phong %g phong_size %g\n", shine, phong_pow);
  704.      if (ks != 0)
  705.         fprintf(outfile, "   reflection %g\n", ks);
  706.      if (t != 0)
  707.         fprintf(outfile, "   refraction %g ior %g\n", t, i_of_r);
  708.      if (format == OUTPUT_POVRAY_15)
  709.         fprintf(outfile, "   }\n");
  710.      fprintf(outfile, "   }\n");
  711.      break;
  712.       case OUTPUT_POLYRAY:
  713.          txname = (char *)malloc(7*sizeof(char));
  714.          if (txname == NULL) {
  715.             fprintf(outfile, "Failed to allocate texture name %d\n",
  716.                    texture_count);
  717.             exit(1);
  718.             }
  719.          sprintf(txname, "txt%03d", texture_count++);
  720.          txname[6] = '\0';
  721.          fprintf(outfile, "define %s\n", txname);
  722.          fprintf(outfile, "texture {\n");
  723.          fprintf(outfile, "   surface {\n");
  724.          fprintf(outfile, "      ambient <%g, %g, %g>, %g\n",
  725.                 color->x, color->y, color->z, ka);
  726.          fprintf(outfile, "      diffuse <%g, %g, %g>, %g\n",
  727.                 color->x, color->y, color->z, kd);
  728.      if (shine != 0) {
  729.         fprintf(outfile, "      specular white, %g\n", shine);
  730.         fprintf(outfile, "      microfacet Phong %g\n", ang);
  731.         }
  732.      if (ks != 0)
  733.         fprintf(outfile, "      reflection white, %g\n", ks);
  734.      if (t != 0)
  735.         fprintf(outfile, "      transmission white, %g, %g\n", t, i_of_r);
  736.          fprintf(outfile, "      }\n");
  737.          fprintf(outfile, "   }\n");
  738.          break;
  739.       case OUTPUT_VIVID:
  740.          fprintf(outfile, "surface = {\n");
  741.          fprintf(outfile, "   ambient = %g %g %g;\n",
  742.                  ka * color->x, ka * color->y, ka * color->z, ka);
  743.          fprintf(outfile, "   diffuse = %g %g %g;\n",
  744.                  kd * color->x, kd * color->y, kd * color->z, ka);
  745.      if (shine != 0)
  746.         fprintf(outfile, "   shine = %g %g %g %g;\n",
  747.             phong_pow, shine, shine, shine);
  748.      if (ks != 0)
  749.         fprintf(outfile, "   specular = %g %g %g;\n", ks, ks, ks);
  750.      if (t != 0) {
  751.         fprintf(outfile, "   transparent = %g %g %g;\n",
  752.                  t * color->x, t * color->y, t * color->z);
  753.             fprintf(outfile, "   ior = %g;\n", i_of_r);
  754.             }
  755.          fprintf(outfile, "   }\n");
  756.          break;
  757.       case OUTPUT_QRT:
  758.          fprintf(outfile, "DEFAULT (\n");
  759.          fprintf(outfile, "   amb = (%g,%g,%g),\n",
  760.                  ka * color->x, ka * color->y, ka * color->z, ka);
  761.          fprintf(outfile, "   diff = (%g,%g,%g),\n",
  762.                  kd * color->x, kd * color->y, kd * color->z, ka);
  763.      fprintf(outfile, "   reflect = %g, sreflect = %g,\n",
  764.          shine, phong_pow);
  765.      fprintf(outfile, "   mirror = (%g,%g,%g),\n",
  766.                  ks * color->x, ks * color->y, ks * color->z);
  767.      fprintf(outfile, "   trans = (%g,%g,%g), index = %g,\n",
  768.                  t * color->x, t * color->y, t * color->z, i_of_r);
  769.          fprintf(outfile, "   dither = 0 )\n");
  770.          break;
  771.       case OUTPUT_RAYSHADE:
  772.          txname = (char *)malloc(7*sizeof(char));
  773.          if (txname == NULL) {
  774.             fprintf(outfile, "Failed to allocate texture name %d\n",
  775.                    texture_count);
  776.             exit(1);
  777.             }
  778.          sprintf(txname, "txt%03d", texture_count++);
  779.          txname[6] = '\0';
  780.          fprintf(outfile, "surface %s\n", txname);
  781.          fprintf(outfile, "   ambient %g %g %g\n",
  782.                 ka * color->x, ka * color->y, ka * color->z);
  783.          fprintf(outfile, "   diffuse %g %g %g\n",
  784.                 kd * color->x, kd * color->y, kd * color->z);
  785.      if (shine != 0) {
  786.         fprintf(outfile, "   specular %g %g %g\n", shine, shine, shine);
  787.         fprintf(outfile, "   specpow %g\n", phong_pow);
  788.         }
  789.      if (ks != 0)
  790.         fprintf(outfile, "   reflect %g\n", ks);
  791.      if (t != 0)
  792.         fprintf(outfile, "   transp %g index %g\n", t, i_of_r);
  793.          break;
  794.       }
  795.    texture_name = txname;
  796.    return txname;
  797. }
  798.  
  799. void
  800. lib_output_polygon_cylcone(base_pt, apex_pt, curve_format)
  801.    COORD4 *base_pt, *apex_pt;
  802.    int curve_format;
  803. {
  804.    double  angle, delta_angle, divisor;
  805.    COORD4  axis, dir, norm_axis, start_norm;
  806.    COORD4  norm[4], vert[4], start_radius[4];
  807.    MATRIX  mx;
  808.    int     i;
  809.  
  810.    SUB3_COORD(axis, (*apex_pt), (*base_pt));
  811.    COPY_COORD(norm_axis, axis);
  812.    lib_normalize_coord3(&norm_axis);
  813.  
  814.    SET_COORD(dir, 0, 0, 1);
  815.    CROSS(start_norm, axis, dir);
  816.    start_norm.w = 0.0;
  817.  
  818.    divisor = lib_normalize_coord3(&start_norm);
  819.    if (ABS(divisor) < EPSILON) {
  820.       SET_COORD(dir, 1, 0, 0);
  821.       CROSS(start_norm, axis, dir);
  822.       lib_normalize_coord3(&start_norm);
  823.       }
  824.  
  825.    start_radius[0].x = start_norm.x * base_pt->w;
  826.    start_radius[0].y = start_norm.y * base_pt->w;
  827.    start_radius[0].z = start_norm.z * base_pt->w;
  828.    start_radius[0].w = 0.0;
  829.    ADD3_COORD(vert[0], (*base_pt), start_radius[0]);
  830.  
  831.    start_radius[1].x = start_norm.x * apex_pt->w;
  832.    start_radius[1].y = start_norm.y * apex_pt->w;
  833.    start_radius[1].z = start_norm.z * apex_pt->w;
  834.    start_radius[1].w = 0.0;
  835.    ADD3_COORD(vert[1], (*apex_pt), start_radius[1]);
  836.  
  837.    COPY_COORD4(norm[0], start_norm);
  838.    COPY_COORD4(norm[1], start_norm);
  839.  
  840.    delta_angle = 2.0 * PI / (double)(2*u_resolution);
  841.    for (i=1,angle=0.0;i<=2*u_resolution;++i,angle+=delta_angle) {
  842.       lib_create_axis_rotate_matrix(mx, &norm_axis, angle);
  843.  
  844.       lib_transform_coord(&vert[2], &start_radius[1], mx);
  845.       ADD2_COORD(vert[2], *apex_pt);
  846.       lib_transform_coord(&norm[2], &start_norm, mx);
  847.       lib_output_polypatch(3, vert, norm);
  848.  
  849.       COPY_COORD4(vert[1], vert[2]);
  850.       norm[1] = norm[2];
  851.       lib_transform_coord(&vert[2], &start_radius[0], mx);
  852.       ADD2_COORD(vert[2], *base_pt);
  853.       lib_output_polypatch(3, vert, norm);
  854.  
  855.       COPY_COORD4(vert[0], vert[2]);
  856.       COPY_COORD4(norm[0], norm[2]);
  857.       }
  858. }
  859.  
  860. /*
  861.  * Output cylinder or cone.  A cylinder is defined as having a radius and an
  862.  * axis defined by two points, which also define the top and bottom edge of the
  863.  * cylinder.  A cone is defined similarly, the difference being that the apex
  864.  * and base radii are different.  The apex radius is defined as being smaller
  865.  * than the base radius.  Note that the surface exists without endcaps.
  866.  *
  867.  * If format=OUTPUT_CURVES, output the cylinder/cone in format:
  868.  *     "c"
  869.  *     base.x base.y base.z base_radius
  870.  *     apex.x apex.y apex.z apex_radius
  871.  *
  872.  * If the format=OUTPUT_POLYGONS, the surface is polygonalized and output.
  873.  * (4*OUTPUT_RESOLUTION) polygons are output as rectangles by
  874.  * lib_output_polypatch.
  875.  */
  876. void
  877. lib_output_cylcone(base_pt, apex_pt, curve_format)
  878.    COORD4 *base_pt, *apex_pt;
  879.    int curve_format;
  880. {
  881.    double  angle, divisor;
  882.    COORD4  axis, dir, norm_axis, start_norm;
  883.    COORD4  lip_norm[4], lip_pt[4], start_radius[4];
  884.    MATRIX  mx;
  885.    long    num_pol;
  886.    double  len, cottheta, xang, yang;
  887.  
  888.    if (curve_format == OUTPUT_CURVES) {
  889.       switch (format) {
  890.      case OUTPUT_VIDEO:
  891.         lib_output_polygon_cylcone(base_pt, apex_pt, curve_format);
  892.         break;
  893.          case OUTPUT_NFF:
  894.             fprintf(outfile, "c\n" ) ;
  895.             fprintf(outfile, "%g %g %g %g\n",
  896.                     base_pt->x, base_pt->y, base_pt->z, base_pt->w ) ;
  897.             fprintf(outfile, "%g %g %g %g\n",
  898.                     apex_pt->x, apex_pt->y, apex_pt->z, apex_pt->w ) ;
  899.             break;
  900.          case OUTPUT_POVRAY:
  901.         /* Since POV-Ray uses infinite primitives, we will start
  902.            with a cone aligned with the z-axis (QCone_Z) and figure
  903.            out how to clip and scale it to match what we want */
  904.             if (apex_pt->w < base_pt->w) {
  905.         /* Put the bigger end at the top */
  906.         COPY_COORD4(axis, *base_pt);
  907.         COPY_COORD4(*base_pt, *apex_pt);
  908.         COPY_COORD4(*apex_pt, axis);
  909.         }
  910.         /* Find the axis and axis length */
  911.         SUB3_COORD(axis, *apex_pt, *base_pt);
  912.         len = lib_normalize_coord3(&axis);
  913.         if (len < EPSILON)
  914.            /* Degenerate cone/cylinder */
  915.            break;
  916.         if (ABS(apex_pt->w - base_pt->w) < 0.000001) {
  917.            /* Treat this thing as a cylinder */
  918.                cottheta = 1.0;
  919.            fprintf(outfile, "object {quadric{<1 1 0><0 0 0><0 0 0>-1}\n");
  920.            }
  921.         else {
  922.            /* Determine alignment */
  923.            cottheta = len / (apex_pt->w - base_pt->w);
  924.            fprintf(outfile, "object {quadric{<1 1 -1><0 0 0><0 0 0>0}\n");
  925.            }
  926.         fprintf(outfile, "   clipped_by {\n");
  927.         fprintf(outfile, "      intersection {\n");
  928.         fprintf(outfile, "         plane { <0 0 -1> %g }\n", -base_pt->w);
  929.         fprintf(outfile, "         plane { <0 0  1> %g }\n", apex_pt->w);
  930.         fprintf(outfile, "         } }\n");
  931.             fprintf(outfile, "   translate <0 0 %g>\n", -base_pt->w);
  932.         fprintf(outfile, "   scale <1 1 %g>\n", cottheta);
  933.         len = sqrt(axis.x * axis.x + axis.z * axis.z);
  934.             xang = -180.0 * asin(axis.y) / PI;
  935.         yang = 180.0 * acos(axis.z / len) / PI;
  936.         if (axis.x < 0)
  937.                yang = -yang;
  938.         fprintf(outfile, "   rotate <%g %g 0>\n", xang, yang);
  939.         fprintf(outfile, "   translate <%g %g %g>\n",
  940.             base_pt->x, base_pt->y, base_pt->z);
  941.         if (texture_name != NULL)
  942.                fprintf(outfile, "   texture { %s }", texture_name);
  943.         fprintf(outfile, "   }\n");
  944.             break;
  945.          case OUTPUT_POVRAY_15:
  946.             fprintf(outfile, "object {\n");
  947.         fprintf(outfile, "   cone { apex <%g, %g, %g> apex_radius %g\n",
  948.             apex_pt->x, apex_pt->y, apex_pt->z, apex_pt->w);
  949.         fprintf(outfile, "          base <%g, %g, %g> base_radius %g }\n",
  950.             base_pt->x, base_pt->y, base_pt->z, base_pt->w);
  951.         if (texture_name != NULL)
  952.                fprintf(outfile, "   texture { %s }", texture_name);
  953.         fprintf(outfile, "   }\n");
  954.         break;
  955.          case OUTPUT_POLYRAY:
  956.             fprintf(outfile, "object {");
  957.             if (base_pt->w == apex_pt->w)
  958.                fprintf(outfile, " cylinder <%g, %g, %g>, <%g, %g, %g>, %g",
  959.                       base_pt->x, base_pt->y, base_pt->z,
  960.                       apex_pt->x, apex_pt->y, apex_pt->z, apex_pt->w);
  961.             else
  962.                fprintf(outfile, " cone <%g, %g, %g>, %g, <%g, %g, %g>, %g",
  963.                       base_pt->x, base_pt->y, base_pt->z, base_pt->w,
  964.                  apex_pt->x, apex_pt->y, apex_pt->z, apex_pt->w);
  965.             if (texture_name != NULL)
  966.                fprintf(outfile, " %s", texture_name);
  967.             fprintf(outfile, " }\n");
  968.             break;
  969.          case OUTPUT_VIVID:
  970.             fprintf(outfile, "cone = {");
  971.             fprintf(outfile, " base = %g %g %g; base_radius = %g;\n",
  972.                     base_pt->x, base_pt->y, base_pt->z, base_pt->w);
  973.             fprintf(outfile, " apex = %g %g %g; apex_radius = %g;\n",
  974.                     apex_pt->x, apex_pt->y, apex_pt->z, apex_pt->w);
  975.             fprintf(outfile, "   }\n");
  976.             break;
  977.          case OUTPUT_QRT:
  978.             fprintf(outfile, "BEGIN_BBOX\n");
  979.             lib_output_polygon_cylcone(base_pt, apex_pt, curve_format);
  980.             fprintf(outfile, "END_BBOX\n");
  981.             break;
  982.          case OUTPUT_RAYSHADE:
  983.             fprintf(outfile, "cone ");
  984.             if (texture_name != NULL)
  985.                fprintf(outfile, "%s ", texture_name);
  986.             fprintf(outfile, " %g %g %g %g %g %g %g %g\n",
  987.                     base_pt->w, base_pt->x, base_pt->y, base_pt->z,
  988.                     apex_pt->w, apex_pt->x, apex_pt->y, apex_pt->z);
  989.             break;
  990.          }
  991.       }
  992.    else
  993.       lib_output_polygon_cylcone(base_pt, apex_pt, curve_format);
  994. }
  995.  
  996. void
  997. sq_sphere_val(a1, a2, a3, n, e, u, v, P)
  998.    double a1, a2, a3, n, e, u, v;
  999.    COORD4 *P;
  1000. {
  1001.    double cu, su, cv, sv;
  1002.  
  1003.    cu = cos(u); su = sin(u);
  1004.    cv = cos(v); sv = sin(v);
  1005.    P->x = a1 * POW(ABS(cv), n) * POW(ABS(cu), e) * SGN(cv) * SGN(cu);
  1006.    P->y = a2 * POW(ABS(cv), n) * POW(ABS(su), e) * SGN(cv) * SGN(su);
  1007.    P->z = a3 * POW(ABS(sv), n) * SGN(sv);
  1008. }
  1009.  
  1010. void
  1011. sq_sphere_norm(a1, a2, a3, n, e, u, v, N)
  1012.    double a1, a2, a3, n, e, u, v;
  1013.    COORD4 *N;
  1014. {
  1015.    double cu, su, cv, sv;
  1016.  
  1017.    cu = cos(u); su = sin(u);
  1018.    cv = cos(v); sv = sin(v);
  1019.  
  1020.    /* May be some singularities in the values, lets catch them & put
  1021.       a fudged normal into N */
  1022.    if (e < 2 || n < 2) {
  1023.       if (ABS(cu) < 1.0e-3 || ABS(su) < 1.0e-3 ||
  1024.           ABS(cu) < 1.0e-3 || ABS(su) < 1.0e-3) {
  1025.      SET_COORD(*N, cu*cv, su*cv, sv);
  1026.          lib_normalize_coord3(N);
  1027.      return;
  1028.          }
  1029.       }
  1030.  
  1031.    N->x = a1 * POW(ABS(cv), 2-n) * POW(ABS(cu), 2-e) * SGN(cv) * SGN(cu);
  1032.    N->y = a2 * POW(ABS(cv), 2-n) * POW(ABS(su), 2-e) * SGN(cv) * SGN(su);
  1033.    N->z = a3 * POW(ABS(sv), 2-n) * SGN(sv);
  1034.    lib_normalize_coord3(N);
  1035. }
  1036.  
  1037. void
  1038. lib_output_sq_sphere(center_pt, a1, a2, a3, n, e)
  1039.    COORD4 *center_pt;
  1040.    double a1, a2, a3, n, e;
  1041. {
  1042.    int i, j, u_res, v_res;
  1043.    double u, delta_u, v, delta_v;
  1044.    COORD4 verts[4], norms[4];
  1045.  
  1046.    u_res = 4 * u_resolution;
  1047.    v_res = 4 * v_resolution;
  1048.    delta_u = 2.0 * PI / (double)u_res;
  1049.    delta_v = PI / (double)v_res;
  1050.  
  1051.    for (i=0,u=0.0;i<u_res;i++,u+=delta_u) {
  1052.       for (j=0,v=-PI/2.0;j<v_res;j++,v+=delta_v) {
  1053.          if (j == 0) {
  1054.         sq_sphere_val(a1, a2, a3, n, e, u, v, &verts[0]);
  1055.         sq_sphere_norm(a1, a2, a3, n, e, u, v, &norms[0]);
  1056.         sq_sphere_val(a1, a2, a3, n, e, u, v+delta_v, &verts[1]);
  1057.         sq_sphere_norm(a1, a2, a3, n, e, u, v+delta_v, &norms[1]);
  1058.         sq_sphere_val(a1, a2, a3, n, e, u+delta_u, v+delta_v, &verts[2]);
  1059.         sq_sphere_norm(a1, a2, a3, n, e, u+delta_u, v+delta_v, &norms[2]);
  1060.         ADD3_COORD(verts[0], verts[0], *center_pt);
  1061.         ADD3_COORD(verts[1], verts[1], *center_pt);
  1062.         ADD3_COORD(verts[2], verts[2], *center_pt);
  1063.             lib_output_polypatch(3, verts, norms);
  1064.             }
  1065.          else if (j == v_res-1) {
  1066.         sq_sphere_val(a1, a2, a3, n, e, u, v, &verts[0]);
  1067.         sq_sphere_norm(a1, a2, a3, n, e, u, v, &norms[0]);
  1068.         sq_sphere_val(a1, a2, a3, n, e, u, v+delta_v, &verts[1]);
  1069.         sq_sphere_norm(a1, a2, a3, n, e, u, v+delta_v, &norms[1]);
  1070.         sq_sphere_val(a1, a2, a3, n, e, u+delta_u, v, &verts[2]);
  1071.         sq_sphere_norm(a1, a2, a3, n, e, u+delta_u, v, &norms[2]);
  1072.         ADD3_COORD(verts[0], verts[0], *center_pt);
  1073.         ADD3_COORD(verts[1], verts[1], *center_pt);
  1074.         ADD3_COORD(verts[2], verts[2], *center_pt);
  1075.             lib_output_polypatch(3, verts, norms);
  1076.             }
  1077.          else {
  1078.         sq_sphere_val(a1, a2, a3, n, e, u, v, &verts[0]);
  1079.         sq_sphere_norm(a1, a2, a3, n, e, u, v, &norms[0]);
  1080.         sq_sphere_val(a1, a2, a3, n, e, u, v+delta_v, &verts[1]);
  1081.         sq_sphere_norm(a1, a2, a3, n, e, u, v+delta_v, &norms[1]);
  1082.         sq_sphere_val(a1, a2, a3, n, e, u+delta_u, v+delta_v, &verts[2]);
  1083.         sq_sphere_norm(a1, a2, a3, n, e, u+delta_u, v+delta_v, &norms[2]);
  1084.         ADD3_COORD(verts[0], verts[0], *center_pt);
  1085.         ADD3_COORD(verts[1], verts[1], *center_pt);
  1086.         ADD3_COORD(verts[2], verts[2], *center_pt);
  1087.             lib_output_polypatch(3, verts, norms);
  1088.         COPY_COORD(verts[1], verts[2]);
  1089.         COPY_COORD(norms[1], norms[2]);
  1090.         sq_sphere_val(a1, a2, a3, n, e, u+delta_u, v, &verts[2]);
  1091.         sq_sphere_norm(a1, a2, a3, n, e, u+delta_u, v, &norms[2]);
  1092.         ADD3_COORD(verts[2], verts[2], *center_pt);
  1093.             lib_output_polypatch(3, verts, norms);
  1094.             }
  1095.          }
  1096.       }
  1097. }
  1098.  
  1099. void
  1100. lib_output_polygon_sphere(center_pt)
  1101.    COORD4 *center_pt;
  1102. {
  1103.    double  angle;
  1104.    COORD4  edge_norm[3], edge_pt[3];
  1105.    long    num_face, num_edge, num_tri, num_vert;
  1106.    COORD4  *x_axis, *y_axis, **pt;
  1107.    COORD4  mid_axis;
  1108.    MATRIX  rot_mx;
  1109.    long    u_pol, v_pol;
  1110.  
  1111.    /* Allocate storage for the polygon vertices */
  1112.    x_axis = (COORD4 *)malloc((u_resolution+1) * sizeof(COORD4));
  1113.    y_axis = (COORD4 *)malloc((v_resolution+1) * sizeof(COORD4));
  1114.    pt     = (COORD4 **)malloc((u_resolution+1) * sizeof(COORD4 *));
  1115.    if (x_axis == NULL || y_axis == NULL || pt == NULL) {
  1116.       fprintf(stderr, "Failed to allocate polygon data\n");
  1117.       exit(1);
  1118.       }
  1119.    for (num_edge=0;num_edge<u_resolution+1;num_edge++) {
  1120.       pt[num_edge] = (COORD4 *)malloc((v_resolution+1) * sizeof(COORD4));
  1121.       if (pt[num_edge] == NULL) {
  1122.      fprintf(stderr, "Failed to allocate polygon data\n");
  1123.      exit(1);
  1124.      }
  1125.       }
  1126.  
  1127.    /* calculate axes used to find grid points */
  1128.    for (num_edge=0;num_edge<=u_resolution;++num_edge) {
  1129.       angle = (PI/4.0) * (2.0*(double)num_edge/u_resolution - 1.0);
  1130.       mid_axis.w = 0.0;
  1131.  
  1132.       mid_axis.x = 1.0; mid_axis.y = 0.0; mid_axis.z = 0.0;
  1133.       lib_create_rotate_matrix(rot_mx, Y_AXIS, angle);
  1134.       lib_transform_coord(&x_axis[num_edge], &mid_axis, rot_mx);
  1135.       }
  1136.  
  1137.    for (num_edge=0;num_edge<=v_resolution;++num_edge) {
  1138.       angle = (PI/4.0) * (2.0*(double)num_edge/v_resolution - 1.0);
  1139.       mid_axis.w = 0.0;
  1140.  
  1141.       mid_axis.x = 0.0; mid_axis.y = 1.0; mid_axis.z = 0.0;
  1142.       lib_create_rotate_matrix(rot_mx, X_AXIS, angle);
  1143.       lib_transform_coord(&y_axis[num_edge], &mid_axis, rot_mx);
  1144.       }
  1145.  
  1146.    /* set up grid of points on +Z sphere surface */
  1147.    for (u_pol=0;u_pol<=u_resolution;++u_pol) {
  1148.       for (v_pol=0;v_pol<=u_resolution;++v_pol) {
  1149.      CROSS(pt[u_pol][v_pol], x_axis[u_pol], y_axis[v_pol]);
  1150.      lib_normalize_coord3(&pt[u_pol][v_pol]);
  1151.      pt[u_pol][v_pol].w = 1.0;
  1152.      }
  1153.       }
  1154.  
  1155.    for (num_face=0;num_face<6;++num_face) {
  1156.       /* transform points to cube face */
  1157.       for (u_pol=0;u_pol<=u_resolution;++u_pol) {
  1158.      for (v_pol=0;v_pol<=v_resolution;++v_pol) {
  1159.         lib_rotate_cube_face(&pt[u_pol][v_pol], Z_AXIS, num_face);
  1160.         }
  1161.      }
  1162.  
  1163.       /* output grid */
  1164.       for (u_pol=0;u_pol<u_resolution;++u_pol) {
  1165.      for (v_pol=0;v_pol<v_resolution;++v_pol) {
  1166.         for (num_tri=0;num_tri<2;++num_tri) {
  1167.            for (num_edge=0;num_edge<3;++num_edge) {
  1168.           num_vert = (num_tri*2 + num_edge) % 4;
  1169.           if (num_vert == 0) {
  1170.              COPY_COORD4(edge_pt[num_edge], pt[u_pol][v_pol]);
  1171.              }
  1172.           else if ( num_vert == 1 ) {
  1173.              COPY_COORD4(edge_pt[num_edge], pt[u_pol][v_pol+1]);
  1174.              }
  1175.           else if ( num_vert == 2 ) {
  1176.              COPY_COORD4(edge_pt[num_edge], pt[u_pol+1][v_pol+1]);
  1177.              }
  1178.           else {
  1179.              COPY_COORD4(edge_pt[num_edge], pt[u_pol+1][v_pol]);
  1180.              }
  1181.           COPY_COORD4(edge_norm[num_edge], edge_pt[num_edge]);
  1182.           edge_pt[num_edge].x = edge_pt[num_edge].x * center_pt->w +
  1183.                     center_pt->x ;
  1184.           edge_pt[num_edge].y = edge_pt[num_edge].y * center_pt->w +
  1185.                     center_pt->y ;
  1186.           edge_pt[num_edge].z = edge_pt[num_edge].z * center_pt->w +
  1187.                     center_pt->z ;
  1188.    
  1189.           }
  1190.            lib_output_polypatch(3, edge_pt, edge_norm);
  1191.            }
  1192.         }
  1193.      }
  1194.       }
  1195.  
  1196.    /* Release any memory used */
  1197.    for (num_edge=0;num_edge<u_resolution+1;num_edge++)
  1198.       free(pt[num_edge]);
  1199.    free(pt);
  1200.    free(y_axis);
  1201.    free(x_axis);
  1202. }
  1203.  
  1204. /*
  1205.  * Output sphere.  A sphere is defined by a radius and center position.
  1206.  *
  1207.  * If format=OUTPUT_CURVES, output the sphere in format:
  1208.  *     "s" center.x center.y center.z radius
  1209.  *
  1210.  * If the format=OUTPUT_POLYGONS, the sphere is polygonalized and output.
  1211.  * The sphere is polygonalized by splitting it into 6 faces (of a cube
  1212.  * projected onto the sphere) and dividing these faces by equally spaced
  1213.  * great circles.  OUTPUT_RESOLUTION affects the number of great circles.
  1214.  * (6*2*u_resolution*v_resolution) polygons are output as triangles
  1215.  * using lib_output_polypatch.
  1216.  */
  1217. void
  1218. lib_output_sphere(center_pt, curve_format)
  1219.    COORD4 *center_pt;
  1220.    int curve_format;
  1221. {
  1222.    if (curve_format == OUTPUT_CURVES) {
  1223.       switch (format) {
  1224.      case OUTPUT_VIDEO:
  1225.         lib_output_polygon_sphere(center_pt);
  1226.         break;
  1227.      case OUTPUT_NFF:
  1228.         fprintf(outfile, "s %g %g %g %g\n",
  1229.             center_pt->x, center_pt->y, center_pt->z, center_pt->w ) ;
  1230.         break;
  1231.      case OUTPUT_POVRAY:
  1232.         fprintf(outfile, "object { sphere { <%g %g %g> %g }",
  1233.             center_pt->x, center_pt->y, center_pt->z, center_pt->w);
  1234.         if (texture_name != NULL)
  1235.            fprintf(outfile, " texture { %s }", texture_name);
  1236.         fprintf(outfile, " }\n");
  1237.         break;
  1238.      case OUTPUT_POVRAY_15:
  1239.         fprintf(outfile, "object { sphere { <%g, %g, %g>, %g }",
  1240.             center_pt->x, center_pt->y, center_pt->z, center_pt->w);
  1241.         if (texture_name != NULL)
  1242.            fprintf(outfile, " texture { %s }", texture_name);
  1243.         fprintf(outfile, " }\n");
  1244.         break;
  1245.      case OUTPUT_POLYRAY:
  1246.         fprintf(outfile, "object { sphere <%g, %g, %g>, %g",
  1247.             center_pt->x, center_pt->y, center_pt->z, center_pt->w);
  1248.         if (texture_name != NULL)
  1249.            fprintf(outfile, " %s", texture_name);
  1250.         fprintf(outfile, " }\n");
  1251.         break;
  1252.      case OUTPUT_VIVID:
  1253.         fprintf(outfile, "sphere = { center = %g %g %g; radius = %g; }\n",
  1254.             center_pt->x, center_pt->y, center_pt->z, center_pt->w);
  1255.         break;
  1256.      case OUTPUT_QRT:
  1257.         fprintf(outfile, "sphere ( loc = (%g, %g, %g), radius = %g )\n",
  1258.             center_pt->x, center_pt->y, center_pt->z, center_pt->w);
  1259.         break;
  1260.          case OUTPUT_RAYSHADE:
  1261.               fprintf(outfile, "sphere ");
  1262.               if (texture_name != NULL)
  1263.                  fprintf(outfile, "%s ", texture_name);
  1264.               fprintf(outfile, " %g %g %g %g\n",
  1265.                       center_pt->w, center_pt->x, center_pt->y, center_pt->z);
  1266.               break;
  1267.      }
  1268.        }
  1269.     else
  1270.       lib_output_polygon_sphere(center_pt);
  1271. }
  1272.  
  1273. static void
  1274. torus_evaluator(trans, theta, phi, r0, r1, vert, norm)
  1275.    MATRIX trans;
  1276.    double theta, phi, r0, r1;
  1277.    COORD4 *vert, *norm;
  1278. {
  1279.    COORD4 v0, v1, tvert, tnorm;
  1280.  
  1281.    /* Compute the position of the point */
  1282.    SET_COORD4(tvert, (r0 + r1 * sin(theta)) * cos(phi),
  1283.                     (r0 + r1 * sin(theta)) * sin(phi),
  1284.                     r1 * cos(theta), 1.0);
  1285.    /* Compute the normal at that point */
  1286.    SET_COORD(v0, r1*cos(theta)*cos(phi),
  1287.                  r1*cos(theta)*sin(phi),
  1288.                  -r1*sin(theta));
  1289.    SET_COORD(v1, -(r0+r1*sin(theta))*sin(phi),
  1290.                  (r0+r1*sin(theta))*cos(phi),
  1291.                  0.0);
  1292.    CROSS(tnorm, v0, v1);
  1293.    tnorm.w = 0.0;
  1294.    lib_normalize_coord3(&tnorm);
  1295.    lib_transform_coord(vert, &tvert, trans);
  1296.    lib_transform_coord(norm, &tnorm, trans);
  1297. }
  1298.  
  1299. void
  1300. lib_output_polygon_torus(center, normal, iradius, oradius)
  1301.    COORD4 *center, *normal;
  1302.    double iradius, oradius;
  1303. {
  1304.    double  divisor, u, v, delta_u, delta_v;
  1305.    MATRIX mx, imx;
  1306.    int i, j;
  1307.    COORD4 vert[4], norm[4];
  1308.  
  1309.    if ((divisor = lib_normalize_coord3(normal)) < 1.0e-8) {
  1310.       fprintf(stderr, "Bad torus normal\n");
  1311.       exit(1);
  1312.       }
  1313.    lib_create_canonical_matrix(mx, imx, center, normal);
  1314.    delta_u = 2.0 * PI / (double)u_resolution;
  1315.    delta_v = 2.0 * PI / (double)v_resolution;
  1316.  
  1317.    /* Dump out polygons */
  1318.    for (i=0,u=0.0;i<u_resolution;i++,u+=delta_u) {
  1319.       for (j=0,v=0.0;j<v_resolution;j++,v+=delta_v) {
  1320.          torus_evaluator(imx, u, v,
  1321.                          iradius, oradius,
  1322.                          &vert[0], &norm[0]);
  1323.          torus_evaluator(imx, u, v+delta_v,
  1324.                          iradius, oradius,
  1325.                          &vert[1], &norm[1]);
  1326.          torus_evaluator(imx, u+delta_u, v+delta_v,
  1327.                          iradius, oradius,
  1328.                          &vert[2], &norm[2]);
  1329.          lib_output_polypatch(3, vert, norm);
  1330.          vert[1] = vert[2];
  1331.          norm[1] = norm[2];
  1332.          torus_evaluator(imx, u+delta_u, v,
  1333.                          iradius, oradius,
  1334.                          &vert[2], &norm[2]);
  1335.          lib_output_polypatch(3, vert, norm);
  1336.          }
  1337.       }
  1338. }
  1339.  
  1340. void
  1341. lib_output_torus(center, normal, iradius, oradius, curve_format)
  1342.    COORD4 *center, *normal;
  1343.    double iradius, oradius;
  1344.    int curve_format;
  1345. {
  1346.    if (curve_format == OUTPUT_CURVES) {
  1347.       switch (format) {
  1348.      case OUTPUT_VIDEO:
  1349.          case OUTPUT_NFF:
  1350.          case OUTPUT_VIVID:
  1351.          case OUTPUT_QRT:
  1352.          case OUTPUT_POVRAY:
  1353.          case OUTPUT_POVRAY_15:
  1354.             lib_output_polygon_torus(center, normal, iradius, oradius);
  1355.             break;
  1356.          case OUTPUT_POLYRAY:
  1357.             fprintf(outfile, "object { torus %g, %g", iradius, oradius);
  1358.             fprintf(outfile, ", <%g, %g, %g>, <%g, %g, %g>",
  1359.                     center->x, center->y, center->z,
  1360.                     normal->x, normal->y, normal->z);
  1361.             if (texture_name != NULL)
  1362.                fprintf(outfile, " %s", texture_name);
  1363.             fprintf(outfile, " }\n");
  1364.             break;
  1365.          case OUTPUT_RAYSHADE:
  1366.               fprintf(outfile, "torus ");
  1367.               if (texture_name != NULL)
  1368.                  fprintf(outfile, "%s ", texture_name);
  1369.               fprintf(outfile, " %g %g %g %g\n",
  1370.                       iradius, center->x, center->y, center->z);
  1371.               break;
  1372.          }
  1373.        }
  1374.     else
  1375.       lib_output_polygon_torus(center, normal, iradius, oradius);
  1376. }
  1377.  
  1378. /* Output box.  A box is defined by a diagonally opposite corners. */
  1379. void
  1380. lib_output_box(p1, p2)
  1381.    COORD4 *p1, *p2;
  1382. {
  1383.    COORD4 box_verts[4];
  1384.  
  1385.    switch (format) {
  1386.       case OUTPUT_VIDEO:
  1387.       case OUTPUT_NFF:
  1388.       case OUTPUT_VIVID:
  1389.      /* Currently no support in nff for a box object, make polygons */
  1390.          /* Sides */
  1391.          SET_COORD(box_verts[0], p1->x, p1->y, p1->z);
  1392.          SET_COORD(box_verts[1], p1->x, p2->y, p1->z);
  1393.          SET_COORD(box_verts[2], p1->x, p2->y, p2->z);
  1394.          SET_COORD(box_verts[3], p1->x, p1->y, p2->z);
  1395.          lib_output_polygon(4, box_verts);
  1396.          SET_COORD(box_verts[3], p2->x, p1->y, p1->z);
  1397.          SET_COORD(box_verts[2], p2->x, p2->y, p1->z);
  1398.          SET_COORD(box_verts[1], p2->x, p2->y, p2->z);
  1399.          SET_COORD(box_verts[0], p2->x, p1->y, p2->z);
  1400.          lib_output_polygon(4, box_verts);
  1401.  
  1402.          /* Front/Back */
  1403.          SET_COORD(box_verts[0], p1->x, p1->y, p1->z);
  1404.          SET_COORD(box_verts[1], p1->x, p2->y, p1->z);
  1405.          SET_COORD(box_verts[2], p2->x, p2->y, p1->z);
  1406.          SET_COORD(box_verts[3], p2->x, p1->y, p1->z);
  1407.          lib_output_polygon(4, box_verts);
  1408.          SET_COORD(box_verts[3], p1->x, p1->y, p2->z);
  1409.          SET_COORD(box_verts[2], p1->x, p2->y, p2->z);
  1410.          SET_COORD(box_verts[1], p2->x, p2->y, p2->z);
  1411.          SET_COORD(box_verts[0], p2->x, p1->y, p2->z);
  1412.          lib_output_polygon(4, box_verts);
  1413.  
  1414.          /* Top/Bottom */
  1415.          SET_COORD(box_verts[0], p1->x, p1->y, p1->z);
  1416.          SET_COORD(box_verts[1], p1->x, p1->y, p2->z);
  1417.          SET_COORD(box_verts[2], p2->x, p1->y, p2->z);
  1418.          SET_COORD(box_verts[3], p2->x, p1->y, p1->z);
  1419.          lib_output_polygon(4, box_verts);
  1420.          SET_COORD(box_verts[3], p1->x, p2->y, p1->z);
  1421.          SET_COORD(box_verts[2], p1->x, p2->y, p2->z);
  1422.          SET_COORD(box_verts[1], p2->x, p2->y, p2->z);
  1423.          SET_COORD(box_verts[0], p2->x, p2->y, p1->z);
  1424.          lib_output_polygon(4, box_verts);
  1425.      break;
  1426.       case OUTPUT_POVRAY:
  1427.          fprintf(outfile, "object { box { <%g %g %g> <%g %g %g> }",
  1428.                  p1->x, p1->y, p1->z, p2->x, p2->y, p2->z);
  1429.          if (texture_name != NULL)
  1430.             fprintf(outfile, " texture { %s }", texture_name);
  1431.          fprintf(outfile, " }\n");
  1432.          break;
  1433.       case OUTPUT_POVRAY_15:
  1434.          fprintf(outfile, "object { box { <%g, %g, %g>, <%g, %g, %g> }",
  1435.                  p1->x, p1->y, p1->z, p2->x, p2->y, p2->z);
  1436.          if (texture_name != NULL)
  1437.             fprintf(outfile, " texture { %s }", texture_name);
  1438.          fprintf(outfile, " }\n");
  1439.          break;
  1440.       case OUTPUT_POLYRAY:
  1441.          fprintf(outfile, "object { box <%g, %g, %g>, <%g, %g, %g>",
  1442.                  p1->x, p1->y, p1->z, p2->x, p2->y, p2->z);
  1443.          if (texture_name != NULL)
  1444.             fprintf(outfile, " %s", texture_name);
  1445.          fprintf(outfile, " }\n");
  1446.          break;
  1447.       case OUTPUT_QRT:
  1448.          fprintf(outfile, "BEGIN_BBOX\n");
  1449.      /* Currently no support in nff for a box object, make polygons */
  1450.          /* Sides */
  1451.          SET_COORD(box_verts[0], p1->x, p1->y, p1->z);
  1452.          SET_COORD(box_verts[1], p1->x, p2->y, p1->z);
  1453.          SET_COORD(box_verts[2], p1->x, p2->y, p2->z);
  1454.          SET_COORD(box_verts[3], p1->x, p1->y, p2->z);
  1455.          lib_output_polygon(4, box_verts);
  1456.          SET_COORD(box_verts[3], p2->x, p1->y, p1->z);
  1457.          SET_COORD(box_verts[2], p2->x, p2->y, p1->z);
  1458.          SET_COORD(box_verts[1], p2->x, p2->y, p2->z);
  1459.          SET_COORD(box_verts[0], p2->x, p1->y, p2->z);
  1460.          lib_output_polygon(4, box_verts);
  1461.  
  1462.          /* Front/Back */
  1463.          SET_COORD(box_verts[0], p1->x, p1->y, p1->z);
  1464.          SET_COORD(box_verts[1], p1->x, p2->y, p1->z);
  1465.          SET_COORD(box_verts[2], p2->x, p2->y, p1->z);
  1466.          SET_COORD(box_verts[3], p2->x, p1->y, p1->z);
  1467.          lib_output_polygon(4, box_verts);
  1468.          SET_COORD(box_verts[3], p1->x, p1->y, p2->z);
  1469.          SET_COORD(box_verts[2], p1->x, p2->y, p2->z);
  1470.          SET_COORD(box_verts[1], p2->x, p2->y, p2->z);
  1471.          SET_COORD(box_verts[0], p2->x, p1->y, p2->z);
  1472.          lib_output_polygon(4, box_verts);
  1473.  
  1474.          /* Top/Bottom */
  1475.          SET_COORD(box_verts[0], p1->x, p1->y, p1->z);
  1476.          SET_COORD(box_verts[1], p1->x, p1->y, p2->z);
  1477.          SET_COORD(box_verts[2], p2->x, p1->y, p2->z);
  1478.          SET_COORD(box_verts[3], p2->x, p1->y, p1->z);
  1479.          lib_output_polygon(4, box_verts);
  1480.          SET_COORD(box_verts[3], p1->x, p2->y, p1->z);
  1481.          SET_COORD(box_verts[2], p1->x, p2->y, p2->z);
  1482.          SET_COORD(box_verts[1], p2->x, p2->y, p2->z);
  1483.          SET_COORD(box_verts[0], p2->x, p2->y, p1->z);
  1484.          lib_output_polygon(4, box_verts);
  1485.          fprintf(outfile, "END_BBOX\n");
  1486.      break;
  1487.       case OUTPUT_RAYSHADE:
  1488.          fprintf(outfile, "box ");
  1489.          if (texture_name != NULL)
  1490.             fprintf(outfile, "%s ", texture_name);
  1491.          fprintf(outfile, " %g %g %g %g %g %g\n",
  1492.                  p1->x, p1->y, p1->z, p2->x, p2->y, p2->z);
  1493.          break;
  1494.       }
  1495. }
  1496.  
  1497.  
  1498. /*
  1499.  * Output polygon.  A polygon is defined by a set of vertices.  With these
  1500.  * databases, a polygon is defined to have all points coplanar.  A polygon has
  1501.  * only one side, with the order of the vertices being counterclockwise as you
  1502.  * face the polygon (right-handed coordinate system).
  1503.  *
  1504.  * The output format is always:
  1505.  *     "p" total_vertices
  1506.  *     vert1.x vert1.y vert1.z
  1507.  *     [etc. for total_vertices polygons]
  1508.  *
  1509.  */
  1510. void
  1511. lib_output_polygon(tot_vert, vert)
  1512.    int tot_vert;
  1513.    COORD4 *vert;
  1514. {
  1515.    int num_vert, i, j;
  1516.    COORD4 x, tvert[3];
  1517.  
  1518.    /* First lets do a couple of checks to see if this is a valid polygon */
  1519.    for (i=0;i<tot_vert;i++) {
  1520.       /* If there are two adjacent coordinates that degenerate then
  1521.          collapse them down to one */
  1522.       SUB3_COORD(x, vert[i], vert[(i+1)%tot_vert]);
  1523.       if (lib_normalize_coord3(&x) < 1.0e-8) {
  1524.          for (j=i;j<tot_vert-1;j++)
  1525.             memcpy(&tvert[j], &tvert[j+1], sizeof(COORD4));
  1526.          tot_vert--;
  1527.          }
  1528.       }
  1529.    
  1530.    if (tot_vert < 3)
  1531.       /* No such thing as a poly that only has two sides */
  1532.       return;
  1533.  
  1534.    switch (format) {
  1535.       case OUTPUT_VIDEO:
  1536.      /* Step through each segment of the polygon, projecting it
  1537.         onto the screen. */
  1538.      break;
  1539.       case OUTPUT_NFF:
  1540.          fprintf(outfile, "p %d\n", tot_vert);
  1541.      for (num_vert=0;num_vert<tot_vert;++num_vert)
  1542.             fprintf(outfile, "%g %g %g\n",
  1543.             vert[num_vert].x, vert[num_vert].y, vert[num_vert].z);
  1544.     break;
  1545.       case OUTPUT_POVRAY:
  1546.       case OUTPUT_POVRAY_15:
  1547.      /* No support in POV-Ray for an arbitrary polygon, we make the
  1548.         assumption that |hs polygon is convex, and split it into
  1549.         triangles */
  1550.      COPY_COORD(tvert[0], vert[0]);
  1551.      for (i=1;i<tot_vert-1;i++) {
  1552.         COPY_COORD(tvert[1], vert[i]);
  1553.         COPY_COORD(tvert[2], vert[i+1]);
  1554.         fprintf(outfile, "object { triangle { ");
  1555.         for (num_vert=0;num_vert<3;++num_vert)
  1556.            if (format == OUTPUT_POVRAY)
  1557.           fprintf(outfile, "<%g %g %g> ",
  1558.              tvert[num_vert].x, tvert[num_vert].y,
  1559.              tvert[num_vert].z);
  1560.            else {
  1561.           fprintf(outfile, "<%g, %g, %g>",
  1562.              tvert[num_vert].x, tvert[num_vert].y,
  1563.              tvert[num_vert].z);
  1564.           if (num_vert < 2)
  1565.              fprintf(outfile, ",");
  1566.           fprintf(outfile, " ");
  1567.           }
  1568.         if (texture_name != NULL)
  1569.            fprintf(outfile, "} texture { %s }", texture_name);
  1570.         fprintf(outfile, " }\n");
  1571.         }
  1572.          break;
  1573.       case OUTPUT_POLYRAY:
  1574.          fprintf(outfile, "object { polygon %d,", tot_vert);
  1575.          for (num_vert = 0; num_vert < tot_vert; num_vert++) {
  1576.             fprintf(outfile, " <%g, %g, %g>",
  1577.                    vert[num_vert].x, vert[num_vert].y, vert[num_vert].z);
  1578.             if (num_vert < tot_vert-1)
  1579.                fprintf(outfile, ", ");
  1580.             }
  1581.          if (texture_name != NULL)
  1582.             fprintf(outfile, " %s", texture_name);
  1583.          fprintf(outfile, " }\n");
  1584.          break;
  1585.       case OUTPUT_VIVID:
  1586.          fprintf(outfile, "polygon = { points = %d;", tot_vert);
  1587.          for (num_vert = 0; num_vert < tot_vert; num_vert++)
  1588.             fprintf(outfile, " vertex = %g %g %g;",
  1589.                    vert[num_vert].x, vert[num_vert].y, vert[num_vert].z);
  1590.          fprintf(outfile, " }\n");
  1591.          break;
  1592.       case OUTPUT_QRT:
  1593.      /* No support in QRT for an arbitrary polygon, we make the
  1594.         assumption that ths polygon is convex, and split it into
  1595.         triangles */
  1596.      COPY_COORD(tvert[0], vert[0]);
  1597.      for (i=1;i<tot_vert-1;i++) {
  1598.         COPY_COORD(tvert[1], vert[i]);
  1599.         COPY_COORD(tvert[2], vert[i+1]);
  1600.         fprintf(outfile, "TRIANGLE ( ");
  1601.             fprintf(outfile, "loc = (%g, %g, %g), ",
  1602.               tvert[0].x, tvert[0].y, tvert[0].z);
  1603.             fprintf(outfile, "vect1 = (%g, %g, %g), ",
  1604.               tvert[1].x - tvert[0].x, tvert[1].y - tvert[0].y,
  1605.                       tvert[1].z - tvert[0].z);
  1606.             fprintf(outfile, "vect2 = (%g, %g, %g) ",
  1607.               tvert[2].x - tvert[0].x, tvert[2].y - tvert[0].y,
  1608.                       tvert[2].z - tvert[0].z);
  1609.         fprintf(outfile, " );\n");
  1610.         }
  1611.          break;
  1612.       case OUTPUT_RAYSHADE:
  1613.          fprintf(outfile, "polygon ");
  1614.          if (texture_name != NULL)
  1615.             fprintf(outfile, "%s ", texture_name);
  1616.          for (num_vert=0;num_vert<tot_vert;num_vert++)
  1617.             fprintf(outfile, "%g %g %g ",
  1618.                    vert[num_vert].x, vert[num_vert].y, vert[num_vert].z);
  1619.          fprintf(outfile, "\n");
  1620.          break;
  1621.       }
  1622. }
  1623.  
  1624.  
  1625. /*
  1626.  * Output polygonal patch.  A patch is defined by a set of vertices and their
  1627.  * normals.  With these databases, a patch is defined to have all points
  1628.  * coplanar.  A patch has only one side, with the order of the vertices being
  1629.  * counterclockwise as you face the patch (right-handed coordinate system).
  1630.  *
  1631.  * The output format is always:
  1632.  *     "pp" total_vertices
  1633.  *     vert1.x vert1.y vert1.z norm1.x norm1.y norm1.z
  1634.  *     [etc. for total_vertices polygonal patches]
  1635.  *
  1636.  */
  1637. void
  1638. lib_output_polypatch(tot_vert, vert, norm)
  1639.    int tot_vert;
  1640.    COORD4 *vert, *norm;
  1641. {
  1642.    int num_vert;
  1643.  
  1644.    switch (format) {
  1645.       case OUTPUT_VIDEO:
  1646.      lib_output_polygon(tot_vert, vert);
  1647.      break;
  1648.       case OUTPUT_NFF:
  1649.      fprintf(outfile, "pp %d\n", tot_vert);
  1650.      for (num_vert=0;num_vert<tot_vert;++num_vert) {
  1651.          fprintf(outfile, "%g %g %g %g %g %g\n",
  1652.              vert[num_vert].x, vert[num_vert].y, vert[num_vert].z,
  1653.              norm[num_vert].x, norm[num_vert].y, norm[num_vert].z);
  1654.          }
  1655.      break;
  1656.       case OUTPUT_POVRAY:
  1657.       case OUTPUT_POVRAY_15:
  1658.          if (tot_vert != 3) {
  1659.             fprintf(outfile, "Smooth triangles must have 3 vertices\n");
  1660.             exit(1);
  1661.             }
  1662.          fprintf(outfile, "object { smooth_triangle { ");
  1663.      for (num_vert=0;num_vert<tot_vert;++num_vert)
  1664.         if (format == OUTPUT_POVRAY)
  1665.            fprintf(outfile, "<%g %g %g> <%g %g %g> ",
  1666.               vert[num_vert].x, vert[num_vert].y, vert[num_vert].z,
  1667.               norm[num_vert].x, norm[num_vert].y, norm[num_vert].z);
  1668.         else {
  1669.            fprintf(outfile, "<%g, %g, %g>, <%g, %g, %g>",
  1670.               vert[num_vert].x, vert[num_vert].y, vert[num_vert].z,
  1671.               norm[num_vert].x, norm[num_vert].y, norm[num_vert].z);
  1672.            if (num_vert < 2)
  1673.           fprintf(outfile, ",");
  1674.            fprintf(outfile, " ");
  1675.            }
  1676.      fprintf(outfile, "}");
  1677.          if (texture_name != NULL)
  1678.             fprintf(outfile, " texture { %s }", texture_name);
  1679.          fprintf(outfile, " }\n");
  1680.          break;
  1681.       case OUTPUT_POLYRAY:
  1682.          if (tot_vert != 3) {
  1683.             fprintf(outfile, "Patches must have 3 vertices, input was %d\n",
  1684.                     tot_vert);
  1685.             exit(1);
  1686.             }
  1687.          fprintf(outfile, "object { patch ");
  1688.      for (num_vert=0;num_vert<tot_vert;++num_vert) {
  1689.         fprintf(outfile, "<%g, %g, %g>, <%g, %g, %g>",
  1690.            vert[num_vert].x, vert[num_vert].y, vert[num_vert].z,
  1691.            norm[num_vert].x, norm[num_vert].y, norm[num_vert].z);
  1692.         if (num_vert<2)
  1693.            fprintf(outfile, ", ");
  1694.         }
  1695.          if (texture_name != NULL)
  1696.             fprintf(outfile, " %s", texture_name);
  1697.          fprintf(outfile, " }\n");
  1698.          break;
  1699.       case OUTPUT_VIVID:
  1700.          if (tot_vert != 3) {
  1701.             fprintf(outfile, "Patches must have 3 vertices, input was %d\n",
  1702.                     tot_vert);
  1703.             exit(1);
  1704.             }
  1705.          fprintf(outfile, "patch = {");
  1706.      for (num_vert=0;num_vert<tot_vert;++num_vert) {
  1707.         fprintf(outfile, " vertex = %g %g %g; normal = %g %g %g;",
  1708.            vert[num_vert].x, vert[num_vert].y, vert[num_vert].z,
  1709.            norm[num_vert].x, norm[num_vert].y, norm[num_vert].z);
  1710.         }
  1711.          fprintf(outfile, " }\n");
  1712.          break;
  1713.       case OUTPUT_QRT:
  1714.          /* No smooth patches in QRT, use flat triangles */
  1715.          lib_output_polygon(tot_vert, vert);
  1716.          break;
  1717.       case OUTPUT_RAYSHADE:
  1718.          if (tot_vert != 3) {
  1719.             fprintf(outfile, "Smooth triangles must have 3 vertices, not %d\n",
  1720.                     tot_vert);
  1721.             exit(1);
  1722.             }
  1723.      fprintf(outfile, "triangle %d\n", tot_vert);
  1724.      for (num_vert=0;num_vert<tot_vert;++num_vert) {
  1725.          fprintf(outfile, "%g %g %g %g %g %g ",
  1726.              vert[num_vert].x, vert[num_vert].y, vert[num_vert].z,
  1727.              norm[num_vert].x, norm[num_vert].y, norm[num_vert].z);
  1728.          }
  1729.          fprintf(outfile, "\n");
  1730.      break;
  1731.       }
  1732. }
  1733.